package com.losalpes.catalog;

import com.losalpes.persistence.IPersistenceServices;
import com.losalpes.persistence.entity.ItemCompra;
import com.losalpes.persistence.entity.Mueble;
import com.losalpes.persistence.entity.TipoMueble;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.model.SelectItem;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

/**
 * Clase que permite manejar la logica de negocio del catalogo
 * @author Henry.Quiroga
 */
@Stateless
@DeclareRoles({"Administrador"})
public class CatalogService implements ICatalogService {

    @EJB
    IPersistenceServices persistenceServices;
    @Resource(mappedName = "jms/PromocionFactory")
    private ConnectionFactory connectionFactory;
    @Resource(mappedName = "jms/PromocionTopic")
    private Topic topic;

    

    /**
     * constructor de la clase
     */
    public CatalogService() {
    }

    

    /**
     * Guarda un mueble en bd
     * @param mueble el mueble a cambiar
     * @return confirmacion
     */
    @RolesAllowed({"Administrador"})
    public void save(Mueble mueble) {
        if (mueble.getId() != 0) {
            persistenceServices.update(mueble);
        } else {
            persistenceServices.create(mueble);
        }
    }

    /**
     * permite almacentar la informacion de los muebles, promociones y notificar las promociones
     * @param mueble el muenle de entrada
     * @return confirmacion
     */
    @RolesAllowed({"Administrador"})
    public void saveWithNotification(Mueble mueble) {
        if (mueble.getId() != 0) {
            persistenceServices.update(mueble);
        } else {
            persistenceServices.create(mueble);
        }

        try {
            notificarCreacionPromocion(mueble);
        } catch (JMSException ex) {
            Logger.getLogger(CatalogService.class.getName()).log(Level.SEVERE, "Error al enviar la notificacion de la promocion del producto", ex);
        }
    }

    /**
     * Borra un mueble
     * @param cMueble el mueble a borrar
     */
    @RolesAllowed({"Administrador"})
    public void delete(Mueble mueble) {
        persistenceServices.delete(mueble);
    }

    /**
     * Verifica si la referencia del mueble a almacenar existe
     * @param mueble el mueble a revkisar
     * @return verdadero o falso
     */
    public boolean existeReferencia(Mueble mueble) {
        for (Mueble aux : (List<Mueble>) persistenceServices.findAll(Mueble.class)) {
            if (aux.getReferencia().equals(mueble.getReferencia())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Lista de todos los muebles
     * @return un List con todos los muebles
     */
    public List<Mueble> findAllMuebles() {
        return persistenceServices.findAll(Mueble.class);
    }

    /**
     * Permite obtener una lista de muebles a partir de una consulta
     * @param muebleBusqueda  el muble con la informacion parametro
     * @return Lista con los muebles
     */
    public List<Mueble> findMuebles(Mueble muebleBusqueda) {
        String sql = "Select m from Mueble m where 1=1 ";

        ArrayList<String> parametrosNombre = new ArrayList<String>();
        ArrayList<Object> parametrosValor = new ArrayList<Object>();

        if (muebleBusqueda.getReferencia() != null && !muebleBusqueda.getReferencia().equals("")) {
            sql += " and m.referencia like :pReferencia";
            parametrosNombre.add("pReferencia");
            parametrosValor.add("%" + muebleBusqueda.getReferencia() + "%");
        }

        if (muebleBusqueda.getNombre() != null && !muebleBusqueda.getNombre().equals("")) {
            sql += " and m.nombre like :pNombre";
            parametrosNombre.add("pNombre");
            parametrosValor.add("%" + muebleBusqueda.getNombre() + "%");
        }

        if (muebleBusqueda.getTipo() != null && !muebleBusqueda.getTipo().equals(TipoMueble.Seleccione)) {
            sql += " and m.tipo = :pTipo";
            parametrosNombre.add("pTipo");
            parametrosValor.add(muebleBusqueda.getTipo());
        }

        return persistenceServices.findQuery(sql, parametrosNombre, parametrosValor);
    }

    /**
     * obtiene el mueble a partir de la referencia
     * @param la referencia del muble
     * @return el mueble encontrado
     */
    public Mueble getMueble(Long id) {
        return (Mueble) persistenceServices.findById(Mueble.class, id);
    }

    /**
     *
     * @return
     */
    public SelectItem[] getTiposMuebles() {
        TipoMueble[] tipos = TipoMueble.values();
        SelectItem[] sitems = new SelectItem[tipos.length];
        for (int i = 0; i < sitems.length; i++) {
            sitems[i] = new SelectItem(tipos[i]);
        }
        return sitems;
    }

    /**
     * Crea el mensaje de promocion que se notificara
     * @param session sesion con la que se enviara el mensaje
     * @mueble Mueble al que se le hace la promocion
     * @return mensaje
     */
    private Message createPromocionMessage(Session session, Mueble mueble) throws JMSException {
        long id = mueble.getId();
        String msg = Long.toString(id);
        TextMessage tm = session.createTextMessage(msg);
        return tm;
    }

    /**
     * Verifica si hay existencias para realizar la compra
     * @param items items de la compra
     * @return Si esta esta en blanco es porque si hay disponibilidad de todos
     * los productos
     */
    public String verificarExistencias(ArrayList<ItemCompra> items) {
        String mensaje = "";
        for (ItemCompra item : items) {
            if (item.getMueble().getCantidad() < item.getCantidad()) {
                mensaje += "No hay stock suficiente para el mueble  " + item.getMueble().getNombre() + " (" + item.getMueble().getReferencia() + ")\n";
            }
        }
        return mensaje;
    }

    /**
     * Permite actualizar el inventario en cantidades y valores
     * @param items la lista de lositems que van a descargarse del inventario
     * @return vacio si todo esta bien
     */
    @RolesAllowed({"Administrador"})
    public void actualizarInventario(ArrayList<ItemCompra> items) {
        for (ItemCompra item : items) {
            item.getMueble().setCantidad(item.getMueble().getCantidad() - item.getCantidad());
            save(item.getMueble());
        }
    }

    /**
     * Se encarga de obtener el mensaje y enviarlo
     * @param mueble el mueble al que se le hace la promocion     *
     */
    private void notificarCreacionPromocion(Mueble mueble) throws JMSException {
        Connection connection = connectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer messageProducer = session.createProducer((Destination) topic);
        try {
            messageProducer.send(createPromocionMessage(session, mueble));
        } catch (JMSException ex) {
            Logger.getLogger(CatalogService.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error cerrando la sesión", e);
                }
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}
